package com.marianhello.bgloc;

import android.Manifest;
import android.app.AlarmManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.PowerManager;
import android.os.SystemClock;
import android.support.v4.app.ActivityCompat;
import android.util.Log;

import org.json.JSONException;
import org.json.JSONObject;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class SensorMonitor {
  private static final String TAG = "SensorMonitor";
  private final PowerManager.WakeLock mWakeLock;
  private SensorManager mSensorManager;
  private   AlarmManager alarmManager;
  private Sensor mAccelerometer;
  private TestSensorListener mSensorListener;
  LocationService context;
  Config config;
  private GPSLocationListener listener;

  public SensorMonitor(Context context) {
    this.context = (LocationService) context;
    // 初始化传感器
    mSensorListener = new TestSensorListener();
    mSensorManager = (SensorManager) this.context.getSystemService(Context.SENSOR_SERVICE);
    if (mSensorManager != null){
      mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
      // 注册传感器监听函数
      mSensorManager.registerListener(mSensorListener, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
    }

    alarmManager = (AlarmManager) context.getSystemService(context.ALARM_SERVICE);

    PowerManager manager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
    mWakeLock = manager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);// CPU保存运行
    IntentFilter offFilter = new IntentFilter();// 屏幕熄掉后依然运行
    offFilter.addAction(Intent.ACTION_SCREEN_OFF);
    context.registerReceiver(screenOffReceiver, offFilter);

    IntentFilter onFilter = new IntentFilter();// 屏幕亮后依然运行
    onFilter.addAction(Intent.ACTION_SCREEN_ON);
    context.registerReceiver(screenOnReceiver, onFilter);
  }

  private static long previousTime = 0;
  private double[][] mSenesorInfoArray = new double[10][3];
  private Double[] accValueArray = new Double[10];
  private List<Double> secondAccValueArray = new ArrayList<Double>();
  private double accValue;
  private int count = 0;
  private int secondCount = 0; // 每秒的计数
  private int driveCount = 0;
  private int walkCount = 0;
  private int motionlessCount = 0;
  private double[] currentAcc = new double[3];
  private static final int DRIVE = 1;
  private static final int WALK = 2;
  private static final int MOTIONLESS = 3;
  private static final int UNKNOWN = 4;

  private int gpsMotionlessCount;// long time motionless
  private  boolean isWalkCountDown;   // walk to count down
  private  boolean isMotionlessCountDown; // long time motionless to count down
  private Location[] locationMotionlessArray = new Location[300];// long time motionless

  private LocationManager locationManager;
  private List<Double> speedList = new ArrayList<Double>();
  private Location[] locationWalkArray = new Location[30]; // walk
  private double speedAvg = 0;
  private boolean isDriving = true;
  private int gpsStartCount;
  private boolean isGPSstart;
  private int gpsWalkStopCount;
  private int getStatus(double median) {
    LogUtil.d(TAG, "median: " + median);
    if (median>=0.15529 && median < 2.5528) {
      driveCount++;
    } else {
      driveCount = 0;
    }

    if(median >= 2.5528) {
      walkCount++;
    } else {
      walkCount = 0;
    }
    if(median < 0.15529){
      motionlessCount++;
    } else {
      motionlessCount = 0;
    }

    if (driveCount == 2) {
      driveCount = 0;
      LogUtil.d(TAG, "status: " + "DRIVE");
      return DRIVE;
    }
    if (walkCount == 2) {
      walkCount = 0;
      LogUtil.d(TAG, "status: " + "WALK" );
      if(LocationService.satellitesCount <= 4 ) {
        stopTrip();
      } else {
        isWalkCountDown = true;
      }
      return WALK;
    }
    if (motionlessCount == 2) {
      motionlessCount = 0;
      LogUtil.d(TAG, "status: " + "MOTIONLESS");
      if(LocationService.satellitesCount > 4 ) {
        isMotionlessCountDown = true;
      }
      return MOTIONLESS;
    }
    LogUtil.d(TAG, "status: " + "UNKNOWN" );
    return  UNKNOWN;
  }
  class TestSensorListener implements SensorEventListener {

    @Override
    public void onSensorChanged(SensorEvent event) {
      // 读取加速度传感器数值，values数组0,1,2分别对应x,y,z轴的加速度
      Log.i(TAG, "onSensorChanged: " + event.values[0] + ", " + event.values[1] + ", " + event.values[2]);
      long currentTime = System.currentTimeMillis() / 100; // 每0.1s计算一次
      Log.i(TAG, "currentTime: " + currentTime );
      if (previousTime == 0 ){
        previousTime = currentTime;
      } else if(currentTime == previousTime){
        return;
      }
      Log.i(TAG, "previousTime: " + previousTime +  " currentTime: " + currentTime );
      currentAcc[0] = event.values[0];
      currentAcc[1] = event.values[1];
      currentAcc[2] = event.values[2];
      Log.i(TAG, "currentAcc: " + currentAcc[0] + ", " + currentAcc[1] + " , " + currentAcc[2]);
      secondCount = secondCount + (int) (currentTime - previousTime);
      previousTime = currentTime;
      if (secondCount >= 10){
        secondCount = 0;
        int size = secondAccValueArray.size();
        double secondMedian = Util.median(secondAccValueArray.toArray(new Double[size]));
        Log.i(TAG,"secondMedian : " + secondMedian);
        secondAccValueArray.clear();
        if(count == 10){
          count = 0;
          double median = Util.median(accValueArray);
          Log.i(TAG,"accValueArray : " + Arrays.toString(accValueArray));
          Log.i(TAG,"median : " + median);
          int sensorStatus = getStatus(median);
          Log.i(TAG,"status : " + sensorStatus);
          if (sensorStatus == 1 && LocationService.autoStartStop) {
              openGPS();
          }
        }

        count++;
        LogUtil.d(TAG, "count : " + count);
        accValueArray[count-1] = secondMedian;
      }

      mSenesorInfoArray[secondCount][0] = currentAcc[0];
      mSenesorInfoArray[secondCount][1] = currentAcc[1];
      mSenesorInfoArray[secondCount][2] = currentAcc[2];


      Log.i(TAG,"x : " + currentAcc[0] + " y: " + currentAcc[1] + " z: " + currentAcc[2]);
      if(secondCount == 0) accValue = Util.sqrt(mSenesorInfoArray[secondCount]);
      else
        accValue = Util.deltaSqrt(mSenesorInfoArray[secondCount - 1], mSenesorInfoArray[secondCount]);
      Log.i(TAG,"accValue : " + accValue);
      secondAccValueArray.add(accValue);// 每秒10个(或者少于10个)加速度值
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {

    }
  }
  private BroadcastReceiver screenOffReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
      if(!intent.getAction().equals(Intent.ACTION_SCREEN_OFF)){
          return;
      }
      if (mSensorManager != null) {//取消监听后重写监听，以保持后台运行
        mSensorManager.unregisterListener(mSensorListener);
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        // 注册传感器监听函数
        mSensorManager.registerListener(mSensorListener, mAccelerometer, SensorManager.SENSOR_DELAY_NORMAL);
        LogUtil.d(TAG,"screenOffReceiver -> registerListener");
      }
    }
  };

  private BroadcastReceiver screenOnReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
      if(!intent.getAction().equals(Intent.ACTION_SCREEN_ON)){
        return;
      }
      if (mSensorManager != null) {//取消监听后重写监听，以保持后台运行
        mSensorManager.unregisterListener(mSensorListener);
        mAccelerometer = mSensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
        // 注册传感器监听函数
        mSensorManager.registerListener(mSensorListener, mAccelerometer, SensorManager.SENSOR_DELAY_UI);
        LogUtil.d(TAG,"screenOnReceiver -> registerListener");
      }
    }
  };
  private BroadcastReceiver closeGPSReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
      closeGPS();
    }
  };

  private void openGPS() {

    locationManager = (LocationManager) this.context.getSystemService(Context.LOCATION_SERVICE);

    //开启gps测试
    if(isGPSstart) {// 如果gps已经启动，不需要重复启动
       return;
    }else { // 启动gps
      boolean isGPS = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
      LogUtil.d(TAG, "isGPS is " + isGPS);
      if (isGPS == true) {
        listener = new GPSLocationListener();
        if (ActivityCompat.checkSelfPermission(this.context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this.context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
          return;
        }
        locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000, 0, listener);
        LogUtil.d(TAG, "GPS is started.");
        isGPSstart = true;

        //1秒钟后执行一个任务
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context , 0 ,new Intent("gps_stop_trip"), 0);
        AlarmManager alarmManager = (AlarmManager) context.getSystemService(context.ALARM_SERVICE);
        context.registerReceiver(closeGPSReceiver, new IntentFilter("gps_stop_trip"));
        alarmManager.cancel(pendingIntent);
        int time = 60 * 1000;
        long triggerAtTime = SystemClock.elapsedRealtime() + time;
        alarmManager.setExact(AlarmManager.ELAPSED_REALTIME_WAKEUP,triggerAtTime, pendingIntent);
      }
    }
  }
  private void closeGPS() {
    if(listener != null) {
      locationManager.removeUpdates(listener);
      isGPSstart = false;
      LogUtil.d(TAG, "GPS is stoped.");
    }
  }
  private void transferLocations() {
    this.context.startTransferLocations();
  }
  private void startTrip() {
    LogUtil.d(TAG, "startTrip -> tripId : " + LocationService.tripId + "  onTrip: " + LocationService.onTrip) ;
    if(LocationService.tripId > 0 || LocationService.onTrip){
      return;
    }
    closeGPS();
    isWalkCountDown = false;
    isMotionlessCountDown = false;
    LogUtil.d(TAG, "startTrip :" + LocationService.tripId);
      config = this.context.getConfig();
      JSONObject startBundle = new JSONObject();
      String carId = config.getCarId();
      try {
        startBundle.put("carId",carId);
      } catch (JSONException e) {
        Log.e(TAG, "Couldn't parse bundle from String to JSONObject");
      } catch (NullPointerException e) {
        Log.e(TAG, "Null pointer exception");
      }
      AutoPostStartTripTask startTripTask = new AutoPostStartTripTask();
      startTripTask.execute(startBundle);

  }
  class GPSLocationListener implements LocationListener {

    @Override
    public void onLocationChanged(Location location) {
      isGPSstart = true;
      double speed = location.getSpeed();
      Log.d(TAG,"onLocationChanged -> speed : " + speed);
      LogUtil.d(TAG,"onLocationChanged -> speed : " + speed + " time : " + location.getTime());

      // start
      gpsStart(speed);
      // walk to stop
      if(isWalkCountDown) {
        locationWalkArray[gpsWalkStopCount] = location;
        gpsWalkStopCount++;
      }
      if (gpsWalkStopCount >= locationWalkArray.length){
        gpsWalkStopCount= 0;
        double distance = 0d;
        double speed1 = 0;
        double speed2 = 0;
        Location loc = null;
        for(int i= 0;i<locationWalkArray.length;i++){
          loc = locationWalkArray[i];
          speed1 = loc.getSpeed();
          if(i==0){
            speed2 = speed1;
          }else {
            speed2 = locationWalkArray[i-1].getSpeed();
          }
          if(speed1 > 2.5){
            return;
          }
          if(Math.abs(speed1 - speed2) > 1.5) {
            return;
          }
          distance += locationWalkArray[i].getSpeed();
        }
        LogUtil.d(TAG, "walk to stop for distance: " + distance);
        if(distance < 150){
          stopTrip();
        }
      }
      // motionless to stop
      if(isMotionlessCountDown) {
        locationMotionlessArray[gpsMotionlessCount] = location;
        gpsMotionlessCount++;
      }
      if(gpsMotionlessCount >= locationMotionlessArray.length) {
        isWalkCountDown = false;
        gpsMotionlessCount = 0;
        double distance = 0d;
        double speed1 = 0;
        double speed2 = 0;
        double acc = 0;
        Location loc = null;
        for(int i= 0;i<locationMotionlessArray.length;i++){
          loc = locationMotionlessArray[i];
          speed1 = loc.getSpeed();
          if(i==0){
            speed2 = speed1;
          }else {
            speed2 = locationMotionlessArray[i-1].getSpeed();
          }
          LogUtil.d(TAG, "speed2 : " + speed1);
          if(speed1 > 2.5){
            return;
          }
          acc = Math.abs(speed1 - speed2);
          LogUtil.d(TAG, "acc2 : " + acc);
          if(acc > 1.5) {
            return;
          }
          distance += locationMotionlessArray[i].getSpeed();
        }
        LogUtil.d(TAG, "motionless to stop for distance : " + distance);
        if(distance < 500){
          stopTrip();
        }
      }
    }

    @Override
    public void onStatusChanged(String provider, int status, Bundle extras) {

    }

    @Override
    public void onProviderEnabled(String provider) {

    }

    @Override
    public void onProviderDisabled(String provider) {

    }
  }

  private void gpsStart(double speed) {
    speedList.add(speed);
    gpsStartCount++;
    if(gpsStartCount >= 10){
      for(int i= gpsStartCount - 10;i<gpsStartCount;i++){
        speedAvg += speedList.get(i);
      }
      speedAvg /= 10;

      if (speedAvg > 2.5){
        LogUtil.d(TAG, "It is driving！");
        startTrip();
      }
    }
    if(gpsStartCount >= 60){
      gpsStartCount = 0;
      speedList.clear();
      closeGPS();
    }
  }

  private void stopTrip() {
    LogUtil.d(TAG, "stopTrip -> tripId : " + LocationService.tripId + "  onTrip: " + LocationService.onTrip) ;
    if(LocationService.tripId == 0 || !LocationService.onTrip || !LocationService.autoStartStop){
      return;
    }
    closeGPS();
    isWalkCountDown = false;
    isMotionlessCountDown = false;
    LogUtil.d(TAG, "stopTrip :" + LocationService.tripId);
    this.context.stopTransferLocations();
    JSONObject stopBundle = new JSONObject();
    try {
      stopBundle.put("tripId",LocationService.tripId);
    } catch (JSONException e) {
      Log.e(TAG, "Couldn't parse bundle from String to JSONObject");
    } catch (NullPointerException e) {
      Log.e(TAG, "Null pointer exception");
    }
    AutoPostStopTripTask stopTripTask = new AutoPostStopTripTask();
    stopTripTask.execute(stopBundle);
  }

  private class AutoPostStartTripTask extends AsyncTask<JSONObject, Integer, String> {
    @Override
    protected String doInBackground(JSONObject... strStartBundles) {
      String response = null;
      try {
        response = HttpPostService.postStartTrip(config.getUrl(), strStartBundles[0], config.getHttpHeaders());
      } catch (NullPointerException e) {
        Log.e(TAG, "Null pointer exception");
      } catch (IOException e) {
        Log.e(TAG, e.toString());
      }
      return response;
    }
    @Override
    protected void onPostExecute(String result) {
      try {
        LocationService.tripId = new JSONObject(result).getInt("tripId");
        LogUtil.d(TAG, "AutoPostStartTripTask -> tripId : " + LocationService.tripId);
        LocationService.onTrip = true;
        if(LocationService.tripId > 0) {
          transferLocations();
        }
      } catch (JSONException e) {
        e.printStackTrace();
      }
    }
  }
  private class AutoPostStopTripTask extends AsyncTask<JSONObject, Integer, String> {
    @Override
    protected String doInBackground(JSONObject... strStopBundles) {
      String response = null;
      try {
        response = HttpPostService.postStopTrip(config.getUrl(), strStopBundles[0], config.getHttpHeaders());
      } catch (IOException e) {
        Log.e(TAG, e.toString());
      }
      LocationService.tripId = 0;
      LocationService.onTrip = false;
      return response;
    }
  }
}
